#include <Windows.h>
#include <tchar.h>
#include <assert.h>

const UINT  WM_UMSG_DATA			= (WM_APP + 1001);
const UINT	WM_UMSG_REGISTER		= RegisterWindowMessage(_T("Register_MSG"));
const UINT	WM_UMSG_BROADCAST		= RegisterWindowMessage(_T("BroadCast_MSG"));
const UINT	WM_UMSG_MSGWNDCREATED	= RegisterWindowMessage(_T("MSGWndCreated_MSG"));

typedef void (*FUNPROC)(HWND hWnd, HWND hSender);
struct TCtrlInfo {
	TCHAR		m_szClsName[32];
	TCHAR		m_szText[64];
	UINT		m_ID;
	FUNPROC		m_fnProc;
};

void  OnSendUserMsg(HWND hWnd, HWND hSender)
{
	PostMessage(hWnd, WM_UMSG_DATA, 100, 110);
	
	return;
}

void  OnSendRegisterMsg(HWND hWnd, HWND hSender)
{
	PostMessage(hWnd, WM_UMSG_REGISTER, 200, 220);

	return;
}
void  OnSendBroadcastMsg(HWND hWnd, HWND hSender)
{
	PostMessage(HWND_BROADCAST, WM_UMSG_BROADCAST, 300, 330);

	return;
}

void  OnSendCopyDataMsg(HWND hWnd, HWND hSender)
{
	struct TPerson {
		UINT	m_nAge;
		TCHAR	m_szName[64];
	};
	
	TPerson Person = { 25, _T("Greg.Yi") };
	COPYDATASTRUCT cds;
	cds.dwData	= 1;
	cds.cbData	= sizeof(Person);
	cds.lpData	= &Person;

	SendMessage(hWnd, WM_COPYDATA, (WPARAM)hSender, (LPARAM)&cds);

	return;
}

void  OnSendExitMsg(HWND hWnd, HWND hSender)
{
	PostMessage(hWnd, WM_CLOSE, 0, 0);

	return;
}

void  OnSendExitApp(HWND hWnd, HWND hSender)
{
	PostQuitMessage(0);

	return;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{	
	static TCtrlInfo CtrlsInfo[] = { 
		{_T("Button"),		_T("User Message"),			1001,		OnSendUserMsg},
		{_T("Button"),		_T("Register Message"),		1002,		OnSendRegisterMsg},
		{_T("Button"),		_T("Broadcast Message"),	1003,		OnSendBroadcastMsg},
		{_T("Button"),		_T("CopyData Message"),		1004,		OnSendCopyDataMsg},
		{_T("Button"),		_T("[Exit] Message"),		1005,		OnSendExitMsg},
		{_T("Button"),		_T("Exit App"),				1006,		OnSendExitApp},

	};
	switch (nMsg)
	{
		case WM_CREATE:
		{
			//--: Move Main wnd to center of screen
			RECT rtMainWnd;
			GetClientRect(hWnd, &rtMainWnd);
			UINT nSrnWidth		= GetSystemMetrics(SM_CXFULLSCREEN);
			UINT nSrnHeight		= GetSystemMetrics(SM_CYFULLSCREEN);
			UINT nWndWidth		= (rtMainWnd.right - rtMainWnd.left);
			UINT nWndHeight		= (rtMainWnd.bottom - rtMainWnd.top);
			UINT nLeft			= (nSrnWidth - nWndWidth) / 2;
			UINT nTop			= (nSrnHeight - nWndHeight) / 2;
			MoveWindow(hWnd, nLeft, nTop, nWndWidth, nWndHeight, TRUE);

			int nWidth	= 150;
			int nHeight	= 50;
			int nRow	= 0;
			int nCol	= 0;
			for (int ii = 0; ii < sizeof(CtrlsInfo) / sizeof(*CtrlsInfo); ii++)
			{
				CreateWindow(CtrlsInfo[ii].m_szClsName, CtrlsInfo[ii].m_szText, WS_VISIBLE|WS_CHILD, 
							 nCol * (nWidth + 10), nRow * 60, nWidth, nHeight, hWnd, (HMENU)CtrlsInfo[ii].m_ID, NULL, NULL);
				EnableWindow(GetDlgItem(hWnd, CtrlsInfo[ii].m_ID), FALSE);
				if ((0 != nCol) && (0 == nCol % 4))
				{
					nRow++;
					nCol = 0;
				} else {
					nCol++;
				}
				
			}
			
			break;
		}
		case WM_COMMAND:
		{			
			HWND hMsgWnd = FindWindowEx(HWND_MESSAGE, NULL, _T("Win32App"), NULL);
			for (int ii = 0; ii < sizeof(CtrlsInfo) / sizeof(*CtrlsInfo); ii++)
			{
				if (wParam == CtrlsInfo[ii].m_ID)
				{
					CtrlsInfo[ii].m_fnProc(hMsgWnd, hWnd);
					
					break;
				}
			}
			break;
		}
		case WM_PAINT:
		{
			PAINTSTRUCT pt;
			HDC hDC = BeginPaint(hWnd, &pt);

			EndPaint(hWnd, &pt);
			return 0;
		}
		case WM_LBUTTONDOWN:
		{
			PostMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, lParam);
			break;
		}
		case WM_DESTROY:
		{			
			PostQuitMessage(0);
			break;
		}
	}

	if (WM_UMSG_BROADCAST == nMsg)
	{
		TCHAR szTmp[129];
		_stprintf(szTmp, _T("Demo0050Ex Broadcast Message -- wParam: %d lParam: %d"), wParam, (LPTSTR)lParam);
		MessageBox(NULL, szTmp, _T("Demo0050Ex"), MB_OK);
	} else if (WM_UMSG_MSGWNDCREATED == nMsg) {
		HWND hMsgWnd = FindWindowEx(HWND_MESSAGE, NULL, _T("Win32App"), NULL);
		for (int ii = 0; ii < sizeof(CtrlsInfo) / sizeof(*CtrlsInfo); ii++)
		{
			EnableWindow(GetDlgItem(hWnd, CtrlsInfo[ii].m_ID), (0 == lParam) ? TRUE : FALSE);
		}
	}

	return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
}

//////////////////////////////////////////////////////////////////////////
bool RegisterWndClass(const TCHAR* szClsName, WNDPROC fnWndProc)
{
	WNDCLASSEX wcs		= {0};
	wcs.cbSize			= sizeof(WNDCLASSEX);
	wcs.hbrBackground	= (HBRUSH)GetStockObject(COLOR_APPWORKSPACE);
	wcs.lpszClassName	= szClsName;
	wcs.lpfnWndProc		= fnWndProc;
	wcs.hCursor			= LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
	wcs.hIcon			= LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_APPLICATION));
	wcs.style			= CS_VREDRAW|CS_HREDRAW;
	
	return (0 != RegisterClassEx(&wcs));
}

//////////////////////////////////////////////////////////////////////////
HWND CreateWnd(const TCHAR* szClsName, const TCHAR* szWndCaption, HWND hParent = NULL, 
			   DWORD dwStyle = WS_POPUP|WS_VISIBLE|WS_SYSMENU|WS_CAPTION, 
			   DWORD dwStyleEx = 0)
{
	if (NULL != szClsName)
	{
		HWND hWnd = CreateWindowEx(dwStyleEx, szClsName, szWndCaption, dwStyle, 0, 0, 800, 480, NULL, NULL, GetModuleHandle(NULL), NULL);
	
		if (NULL != hWnd && IsWindow(hWnd))
		{
			return hWnd;
		}
	}
	return NULL;
}

//////////////////////////////////////////////////////////////////////////
void RunMessageLoop()
{
	MSG Msg;
	while (true)
	{
		while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
		{
			if (WM_QUIT == Msg.message)
			{
				return;
			}

			TranslateMessage(&Msg);
			DispatchMessage(&Msg);
		}
	}
}

//////////////////////////////////////////////////////////////////////////
BOOL WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR szCmdLine, int nShowCmd)
{
	const TCHAR* szClsName		= _T("Win32App");
	const TCHAR* szWndCaption	= _T("Demo0050Ex");

	if (RegisterWndClass(szClsName, WndProc))
	{
		if (NULL != CreateWnd(szClsName, szWndCaption))
		{
			RunMessageLoop();
		}
	}

	return TRUE;
}
